// Author: Zhang Yisong(zhang_yisong@foxmail.com)
#pragma once
#include "pw_async2/coro.h"
#include "pw_async2/coro_or_else_task.h"
#include "pw_preprocessor/arguments.h"
#include "pw_status/status.h"
#include "runnable.hpp"
#if __has_include("pw_log/log.h")
#include "pw_log/log.h"
#define CONFIG_CORO_USE_PW_LOG 1
#endif

namespace coro {
using  Awaitable [[deprecated]] = pw::async2::Coro<pw::Status>;
// using Coro = pw::async2::CoroOrElseTask;

class Coro : public pw::async2::CoroOrElseTask {
public:
  using ErrorStatusHandler = pw::Function<void(pw::Status)>;
  Coro(pw::async2::Coro<pw::Status> &&coro_task, ErrorStatusHandler &&or_else)
      : pw::async2::CoroOrElseTask(
            std::forward<pw::async2::Coro<pw::Status>>(coro_task),
            std::forward<ErrorStatusHandler>(or_else)){};
  Coro(pw::async2::Coro<pw::Status> &&coro_task)
      : pw::async2::CoroOrElseTask(
            std::forward<pw::async2::Coro<pw::Status>>(coro_task),
            [](pw::Status s) {
#if CONFIG_CORO_USE_PW_LOG
              PW_LOG_WARN("Coroutine task failed to execute with status: %s",
                          s.str());
#endif
            }) {
  }
};

using AsyncStatus = pw::async2::Coro<pw::Status>;
// inline auto Task(
//     Awaitable &&awaitable,
//     pw::Function<void(pw::Status)> &&or_else = [](pw::Status s) {
// #if CONFIG_CORO_USE_PW_LOG
//       PW_LOG_WARN("Coroutine task failed to execute with status: %s",
//       s.str());
// #endif
//     }) -> pw::async2::CoroOrElseTask {
//   // return pw::async2::CoroOrElseTask(
//   return coro::Coro(std::forward<Awaitable>(awaitable),
//                     std::forward<pw::Function<void(pw::Status)>>(or_else));
// }

#define __CO_TRY(index, co_try, expr) co_try(expr)
#define __CO_TRY_SEP(index, co_try) ;

/// Check the the results, returned with status if not equal to Ok
// #define CORO_TRY(...) PW_DELEGATE_BY_ARG_COUNT(_CORO_TRY, __VA_ARGS__)
#define CORO_TRY(...) PW_APPLY(__CO_TRY, __CO_TRY_SEP, PW_CO_TRY, __VA_ARGS__)

/// Await the awaitable, and check the results, returned with status if not
/// equal to Ok
#define CORO_TRY_AWAIT(awaitable) CORO_TRY(co_await awaitable)

} // namespace coro